package com.zn.opit.tech.easyexcel.controller;

import com.zn.opit.tech.easyexcel.domain.excel.DoctorReportForm;
import com.zn.opit.tech.easyexcel.domain.excel.PhysiotherapyDetail;
import com.zn.opit.tech.easyexcel.exception.EasyExcelException;
import com.zn.opit.tech.easyexcel.exception.EasyExcelExtExceptionTypes;
import com.zn.opit.tech.easyexcel.utils.BeanMapUtil;
import com.zn.opit.tech.easyexcel.utils.ExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
@RequestMapping(value = "/data")
@RestController
public class DataStatController {

    @GetMapping(value = "/export", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void export(HttpServletResponse response) {
        final String filename = "easyexcel-tpl-export-demo.xlsx";

        // 获取要导出的数据列表/这里构造的假的,真实场景中应从数据库查询并转换为ExcelVO
        List<DoctorReportForm> excelVOS = getDoctorReportFormList();

        // 获取列表标题列表
        List<String> propNameCns = ExcelUtil.getPropNameCns(DoctorReportForm.class);
        List<String> propNameEns = ExcelUtil.getPropNameEns(DoctorReportForm.class);

        try (ServletOutputStream out = response.getOutputStream();
             SXSSFWorkbook wb = new SXSSFWorkbook()) {
            SXSSFSheet sheet = wb.createSheet();
            SXSSFRow row = sheet.createRow(0);
            for (int i = 0; i < propNameCns.size(); i++) {
                row.createCell(i).setCellValue(propNameCns.get(i));
            }

            for (DoctorReportForm excelVO : excelVOS) {
                Map<String, Object> excelVOMap = BeanMapUtil.beanToMap(excelVO);
                List<PhysiotherapyDetail> details = excelVO.getPhysiotherapyDetails();
                int size = (!CollectionUtils.isEmpty(details) || details.size() > 1) ? details.size() : 1;
                int beginRowNum = sheet.getLastRowNum() + 1;
                row = sheet.createRow(beginRowNum);
                row.createCell(0).setCellValue(excelVO.getProvinceName());
                int endRowNum = beginRowNum + size - 1;
                // 定义合并范围，参数依次是起始行号、结束行号、起始列号、结束列号
                for (int i = 0; i <= 6; i++) {
                    row.createCell(i).setCellValue((String) excelVOMap.get(propNameEns.get(i)));
                    CellRangeAddress rangeAddress = new CellRangeAddress(beginRowNum, endRowNum, i, i);
                    if (size > 1) sheet.addMergedRegion(rangeAddress);
                }

                // list的特殊处理
                int subRowNum = beginRowNum;
                for (PhysiotherapyDetail detail : details) {
                    List<String> nameEns = ExcelUtil.getPropNameEns(PhysiotherapyDetail.class);
                    Map<String, Object> detailMap = BeanMapUtil.beanToMap(detail);
                    if (subRowNum > beginRowNum) {
                        row = sheet.createRow(sheet.getLastRowNum() + 1);
                    }
                    for (int i = 7; i <= 10; i++) {
                        row.createCell(i).setCellValue((String) detailMap.get(nameEns.get(i - 7)));
                    }
                    subRowNum++;
                }
            }

            // 用流的形式传输
            response.setHeader(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
            // 防止中文乱码
            try {
                response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
            } catch (UnsupportedEncodingException e) {
                throw new EasyExcelException(EasyExcelExtExceptionTypes.ENCODE_NOT_SUPPORTED);
            }
            wb.write(out);
        } catch (IOException e) {
            throw new EasyExcelException(EasyExcelExtExceptionTypes.EXPORT_FAILED);
        }
    }

    // 构造虚假数据
    private static List<DoctorReportForm> getDoctorReportFormList() {
        List<DoctorReportForm> excelVOS = new ArrayList<>();
        excelVOS.add(DoctorReportForm.builder()
                .provinceName("辽宁省").cityName("沈阳市").belongArea("皇家分院").lecturer("李蛋")
                .avgPreDiagnosisRate("0.00%").avgOutputRate("0.00%").whichRound("1")
                .physiotherapyDetails(Arrays.asList(
                        PhysiotherapyDetail.builder()
                                .belongDeptName("皇家二科").deptJoinRoundCnt("1")
                                .preDiagnosisRate("0.00%").outputRate("0.00%").build(),
                        PhysiotherapyDetail.builder()
                                .belongDeptName("皇家一科").deptJoinRoundCnt("1")
                                .preDiagnosisRate("36.42%").outputRate("0.00%").build()))
                .build()
        );
        excelVOS.add(DoctorReportForm.builder()
                .provinceName("河南省").cityName("洛阳市").belongArea("皇家分院").lecturer("梦之花")
                .avgPreDiagnosisRate("0.30%").avgOutputRate("0.21%").whichRound("1")
                .physiotherapyDetails(Arrays.asList(
                        PhysiotherapyDetail.builder()
                                .belongDeptName("皇家八科").deptJoinRoundCnt("1")
                                .preDiagnosisRate("3.20%").outputRate("4.10%").build(),
                        PhysiotherapyDetail.builder()
                                .belongDeptName("皇家九科").deptJoinRoundCnt("1")
                                .preDiagnosisRate("2.50%").outputRate("3.30%").build(),
                        PhysiotherapyDetail.builder()
                                .belongDeptName("皇家十科").deptJoinRoundCnt("1")
                                .preDiagnosisRate("37.42%").outputRate("54.26%").build()))
                .build()
        );
        return excelVOS;
    }
}
